import keyring
import sys
import tkinter as tk
from tkinter import messagebox, filedialog, simpledialog
import pyautogui
import time
import pyperclip
import subprocess
import os
import pandas as pd
import threading
from web_scraper import WebScraper
from cryptography.fernet import Fernet, InvalidToken
from datetime import datetime
import requests

# 创建主窗口
root = tk.Tk()
root.title("小红书自动分发")

# 全局变量
SERVICE_NAME = 'CApp'  # 服务名称用于keyring
SECRET_KEY = b'FzHRmegDD9AXD4FBnDtQMfhPY0G0VdH3iIAdVwzc618='

folders = []  # 所有素材文件
copied_links = []
bowser_folder = 'bowser/'  # 浏览器窗口按钮文件夹路径
redbook_folder = 'redbook/'  # 打开窗口后按钮文件夹路径
bowser_images = [file for file in os.listdir(bowser_folder) if os.path.isfile(os.path.join(bowser_folder, file))]

# 定义变量以存储选择的文件夹路径
selected_folder = tk.StringVar()
dto_file_path = tk.StringVar()  # 用于存储生成的文件路径
folders_count_var = tk.StringVar(value="0")  # 用于存储文件夹数量

count_var = tk.StringVar(value="0")

# 定义一个函数来将消息打印到文本框
def log_message(message):
    log_text.insert(tk.END, message + '\n')
    log_text.see(tk.END)  # 自动滚动到最后

# 密钥相关功能
def get_beijing_time():
    try:
        response = requests.get('http://worldtimeapi.org/api/timezone/Asia/Shanghai', timeout=5)
        response.raise_for_status()
        datetime_str = response.json()['datetime']
        return datetime.fromisoformat(datetime_str).replace(tzinfo=None)
    except Exception as e:
        messagebox.showerror("错误", f"无法获取当前日期: {e}")
        return None

def decrypt_key():
    return keyring.get_password(SERVICE_NAME, 'expiry_key')

def check_date_limit(expiry_date):
    current_date = get_beijing_time()
    if not current_date:
        messagebox.showerror("错误", "无法验证当前时间，请检查网络连接。")
        return False

    if current_date > expiry_date:
        messagebox.showwarning("警告", "该应用程序已过期，请重新输入密钥。")
        return False
    return True

def prompt_for_key(app, secret_key):
    app.withdraw()
    encrypted_key = simpledialog.askstring("输入密钥", "请输入有效的密钥：")
    app.deiconify()
    if encrypted_key:
        fernet = Fernet(secret_key)
        try:
            decrypted_key = fernet.decrypt(encrypted_key.encode()).decode()
            expiry_date = datetime.strptime(decrypted_key, '%Y-%m-%d')
            encrypt_key(encrypted_key)  # 存储新的密钥
            return expiry_date
        except (InvalidToken, ValueError) as e:
            messagebox.showerror("错误", f"无效的密钥格式或解密失败：{e}")
            return prompt_for_key(app, secret_key)
    else:
        sys.exit(1)

def encrypt_key(key):
    keyring.set_password(SERVICE_NAME, 'expiry_key', key)

# 最小化窗口
def mini():
    time.sleep(0.5)
    pyautogui.hotkey('alt', 'space')
    time.sleep(0.3)
    pyautogui.press('n')

# 浏览文件夹
def browse_folder():
    global folders
    global count_var
    # 弹出文件夹选择对话框
    folder_path = filedialog.askdirectory(title="选择要导航的文件夹")
    if folder_path:
        selected_folder.set(folder_path)  # 更新显示选择的文件夹路径
        # 更新 dto_file_path
        dto_path = os.path.join(folder_path, '小红蓝字.dto')
        dto_file_path.set(dto_path)  # 更新 DTO 文件路径显示

        folders = [name for name in os.listdir(selected_folder.get()) if os.path.isdir(os.path.join(selected_folder.get(), name))]
        folders.sort()
        
        # 更新文件夹总数
        folders_count_var.set(str(len(folders)))
        count_var.set("0") # 重置计数


# 定义一个函数来查找图像，并在找不到时等待并重试
def find_image_with_retry(image_path, retries=5, delay=2):
    while True:
        for attempt in range(retries):
            try:
                location = pyautogui.locateCenterOnScreen(image_path)
                if location:
                    return location
            except Exception as e:
                log_message(f"暂未找到按钮：{image_path}")
            time.sleep(delay)
        
        # 显示弹窗
        messagebox.showinfo("继续", "未找到按钮，是否继续重试？")
        log_message("继续重试...")

# 查找打开的浏览器
def find_bowser(image_path):
    bowser_image_path = os.path.join(bowser_folder, image_path)
    print(bowser_image_path, image_path)
    try:
        location = pyautogui.locateCenterOnScreen(bowser_image_path)
        return location
    except Exception as e:
        return None

# 主操作函数
def start_automation_thread():
    automation_thread = threading.Thread(target=start_automation)
    automation_thread.start()

def start_automation():
    global folders
    global bowser_images

    # 筛选打开的浏览器
    bowser_images = [bowser_image for bowser_image in bowser_images if find_bowser(bowser_image)]
    print(bowser_images)

    for bowser_image in bowser_images:
        folder_path = os.path.join(selected_folder.get(), folders[int(count_var.get())])
        output_file_path = os.path.join(folder_path, 'output.txt')
        bowser_image_path = os.path.join(bowser_folder, bowser_image)
        
        browser_button_location = find_image_with_retry(bowser_image_path)
        pyautogui.click(browser_button_location)
        log_message(f"已点击浏览器窗口按钮: {bowser_image}")

        
        time.sleep(0.5)
        # 点击多个按钮
        for img in ['1.png', '2.png', '3.png']:
            redbook_image_path = os.path.join(redbook_folder, img)
            redbook_button_location = find_image_with_retry(redbook_image_path)
            pyautogui.click(redbook_button_location)
            log_message(f"已点击 {img}")
            time.sleep(0.5)
        
        pyautogui.hotkey('alt', 'd')
        pyperclip.copy(folder_path)
        pyautogui.hotkey('ctrl', 'v')
        pyautogui.press('enter')
        log_message(f"已输入文件夹路径并确认: {folder_path}")
        
        time.sleep(0.5)
        for _ in range(4):
            pyautogui.press('tab')
        time.sleep(0.5)

        pyautogui.hotkey('ctrl', 'a')
        log_message("已全选文件")
        pyautogui.press('enter')
        log_message("已确认选择文件")
        
        time.sleep(0.5)
        for _ in range(2):
            pyautogui.press('tab')
        time.sleep(0.5)

        with open(output_file_path, 'r', encoding='utf-8') as file:
            lines = file.readlines()

        if lines:
            first_line = lines[0].strip()
            pyperclip.copy(first_line)
            log_message(f"已复制第一行内容: {first_line}")
            time.sleep(0.5)
            pyautogui.hotkey('ctrl', 'v')
            log_message("已粘贴第一行内容")
            time.sleep(0.5)
            pyautogui.press('tab')
            log_message("已换行")
            
            remaining_lines = ''.join(lines[1:]).strip()
            if remaining_lines:
                pyperclip.copy(remaining_lines)
                log_message(f"已复制第一行以外的内容: {remaining_lines}")
                time.sleep(0.5)
                pyautogui.hotkey('ctrl', 'v')
                log_message("已粘贴第一行以外的内容")
        else:
            log_message(f"{output_file_path} 文件为空或不存在")

        subprocess.run(['start', dto_file_path.get()], shell=True)
        log_message(f"已运行文件: {dto_file_path.get()}")
        time.sleep(0.5)
        pyautogui.hotkey('ctrl', 'v')

        # 最小化
        mini()

        time.sleep(0.5)
        count = int(count_var.get())  # 获取初始的 count 值

        # 在适当位置更新 count_var 的值
        count += 1
        count_var.set(str(count))  # 更新显示框中的 count

        # 判断素材是否还有
        if count >= int(folders_count_var.get()):
            print('截止')
            break # 没有素材就开始下一环节

    # 发布作品
    for bowser_image in bowser_images:
        bowser_image_path = os.path.join(bowser_folder, bowser_image)
        browser_button_location = find_image_with_retry(bowser_image_path)

        pyautogui.click(browser_button_location)
        log_message(f"已点击浏览器窗口按钮: {bowser_image}")


        time.sleep(0.5)
        redbook_image_path = os.path.join(redbook_folder, '4.png')
        redbook_button_location = find_image_with_retry(redbook_image_path)

        pyautogui.moveTo(redbook_button_location.x, redbook_button_location.y, duration=0)
        log_message(f"鼠标已移动到图像位置: ({redbook_button_location.x}, {redbook_button_location.y})")
        pyautogui.scroll(-500)

        time.sleep(1)
        redbook_image_path = os.path.join(redbook_folder, '5.png')
        redbook_button_location = find_image_with_retry(redbook_image_path)
    
        pyautogui.click(redbook_button_location)
        log_message("已点击 '5.png'")

        # 最小化
        mini()

        # 判断素材是否还有
        if count >= int(folders_count_var.get()):
            break # 没有素材就开始下一环节
        time.sleep(0.5)

    # 收集链接
    for bowser_image in bowser_images:
        bowser_image_path = os.path.join(bowser_folder, bowser_image)
        browser_button_location = find_image_with_retry(bowser_image_path)
        if browser_button_location:
            pyautogui.click(browser_button_location)
            log_message(f"已点击浏览器窗口按钮: {bowser_image}")
        else:
            log_message(f"放弃操作：{bowser_image}")
            continue

        time.sleep(0.5)
        redbook_image_path = os.path.join(redbook_folder, '6.png')
        redbook_button_location = find_image_with_retry(redbook_image_path)

        pyautogui.click(redbook_button_location)
        log_message(f"已点击笔记管理按钮: {bowser_image}")


        time.sleep(0.5)
        redbook_image_path = os.path.join(redbook_folder, '7.png')
        redbook_button_location = find_image_with_retry(redbook_image_path)
        pyautogui.click(redbook_button_location.x - 100, redbook_button_location.y)
        log_message("已打开作品")
        time.sleep(0.5)
        pyautogui.hotkey('alt', 'd')
        log_message("聚焦链接")

        # 初始化 copied_link 为 'about:blank' 以启动循环
        copied_link = "about:blank"

        # 循环直到复制到非 'about:blank' 的链接
        while copied_link == "about:blank":
            time.sleep(0.3)
            pyautogui.hotkey('ctrl', 'c')
            log_message("尝试复制链接")
            copied_link = pyperclip.paste()
            if copied_link == "about:blank":
                log_message("检测到链接为 about:blank，等待后重试")

        copied_links.append(copied_link)
        log_message(f"已复制有效链接: {copied_link}")

        # 最小化
        mini()

        # 判断素材是否还有
        if count >= int(folders_count_var.get()):
            break # 没有素材就开始下一环节
        time.sleep(0.5)

    # 保存到Excel文件
    save_to_excel()

# 保存到Excel文件的函数
def save_to_excel():
    excel_file = 'links.xlsx'
    if os.path.exists(excel_file):
        existing_df = pd.read_excel(excel_file)
        existing_links = existing_df['Link'].tolist()
    else:
        existing_links = []

    # all_links = list(set(existing_links + copied_links)) # 去重版
    all_links = existing_links + copied_links # 不去重版
    df = pd.DataFrame(all_links, columns=['Link'])
    df.to_excel(excel_file, index=False)
    log_message(f"已保存收集的链接到 '{excel_file}'")
    messagebox.showinfo("完成", "所有操作已完成")

def process_existing_excel():
    def run_scraper():
        input_file = 'links.xlsx'
        if os.path.exists(input_file):
            output_file = filedialog.asksaveasfilename(
                title="选择导出的Excel文件位置",
                defaultextension=".xlsx",
                filetypes=[("Excel文件", "*.xlsx")]
            )
            if output_file:
                # 创建一个进度条窗口
                progress_window = tk.Toplevel(root)
                progress_window.title("处理中")
                progress_bar = tk.ttk.Progressbar(progress_window, mode='determinate')
                progress_bar.pack(expand=True, fill=tk.BOTH)
                progress_window.geometry("300x50")

                # 使用web_scraper进行数据抓取
                WebScraper.web_scraping(input_file, output_file, progress_bar)

                # 关闭进度条窗口
                progress_window.destroy()
                log_message(f"已完成处理，并保存结果到 '{output_file}'")
                messagebox.showinfo("完成", f"所有操作已完成，处理结果已保存到: {output_file}")
        else:
            messagebox.showerror("错误", f"文件 '{input_file}' 不存在。请确保已生成文件。")

    # 创建并启动新线程来运行run_scraper
    threading.Thread(target=run_scraper).start()

# 添加新按钮以处理现有的Excel文件
button_process_excel = tk.Button(root, text="处理已有Excel文件", command=process_existing_excel)
button_process_excel.grid(row=7, column=0, columnspan=3, pady=10)
# 创建显示文件夹路径的标签
label_folder = tk.Label(root, text="选择的文件夹路径:")
label_folder.grid(row=0, column=0, padx=10, pady=5, sticky="e")

# 创建用于显示选择的文件夹路径的输入框
entry_folder = tk.Entry(root, textvariable=selected_folder, width=50)
entry_folder.grid(row=0, column=1, padx=10, pady=5)

# 创建用于选择文件夹的按钮
button_browse = tk.Button(root, text="浏览", command=browse_folder)
button_browse.grid(row=0, column=2, padx=10, pady=5)

# 创建显示 DTO 文件路径的标签
label_dto = tk.Label(root, text="蓝色话题文件路径:")
label_dto.grid(row=1, column=0, padx=10, pady=5, sticky="e")

# 创建用于显示 DTO 文件路径的输入框
entry_dto = tk.Entry(root, textvariable=dto_file_path, width=50)
entry_dto.grid(row=1, column=1, padx=10, pady=5)

# 创建显示 count 的标签
label_count = tk.Label(root, text="当前计数:")
label_count.grid(row=2, column=0, padx=10, pady=5, sticky="e")

# 创建用于显示和修改 count 的输入框
entry_count = tk.Entry(root, textvariable=count_var, width=10,  state="readonly")
entry_count.grid(row=2, column=1, padx=10, pady=5, sticky="w")

# 创建显示文件夹总数的标签
label_folders_count = tk.Label(root, text="文件夹总数:")
label_folders_count.grid(row=3, column=0, padx=10, pady=5, sticky="e")

# 创建用于显示文件夹总数的输入框（只读）
entry_folders_count = tk.Entry(root, textvariable=folders_count_var, width=10, state="readonly")
entry_folders_count.grid(row=3, column=1, padx=10, pady=5, sticky="w")

# 创建开始自动化操作的按钮
start_button = tk.Button(root, text="开始自动化", command=start_automation_thread)
start_button.grid(row=4, column=0, columnspan=3, pady=20)

# 创建日志显示文本框
log_text = tk.Text(root, wrap='word', height=15, width=60)
log_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)

# 设置所有列的权重，使得它们能够自适应窗口大小变化
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=3)
root.columnconfigure(2, weight=1)

stored_key = None
fernet = Fernet(SECRET_KEY)

while stored_key is None:
    encrypted_key = decrypt_key()
    if encrypted_key:
        try:
            stored_key = fernet.decrypt(encrypted_key.encode()).decode()
            expiry_date = datetime.strptime(stored_key, '%Y-%m-%d')
            break  # 成功解密并解析日期，跳出循环
        except (InvalidToken, ValueError) as e:
            print(f"Decryption failed: {e}")
            messagebox.showerror("错误", "密钥无效或格式不正确，请重新输入。")
            stored_key = None
    else:
        messagebox.showinfo("信息", "没有找到密钥，请输入新密钥。")
        stored_key = None

    if stored_key is None:
        expiry_date = prompt_for_key(root, SECRET_KEY)

if not check_date_limit(expiry_date):
    sys.exit(1)

# 运行主循环
root.mainloop()